package com.nodecollege.cloud.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.nodecollege.cloud.common.UpmsConstants;
import com.nodecollege.cloud.common.constants.NCConstants;
import com.nodecollege.cloud.common.exception.UpmsException;
import com.nodecollege.cloud.common.model.ApiDataPower;
import com.nodecollege.cloud.common.model.LoginUser;
import com.nodecollege.cloud.common.model.NCResult;
import com.nodecollege.cloud.common.model.QueryVO;
import com.nodecollege.cloud.common.model.po.*;
import com.nodecollege.cloud.common.model.vo.LoginVO;
import com.nodecollege.cloud.common.utils.NCUtils;
import com.nodecollege.cloud.common.utils.RedisUtils;
import com.nodecollege.cloud.common.utils.RegularExpUtils;
import com.nodecollege.cloud.common.utils.ThreadUserUtils;
import com.nodecollege.cloud.core.utils.PasswordUtil;
import com.nodecollege.cloud.dao.mapper.UpmsMemberMapper;
import com.nodecollege.cloud.dao.mapper.UpmsTenantMapper;
import com.nodecollege.cloud.dao.mapper.UpmsUserMapper;
import com.nodecollege.cloud.dao.mapper.UpmsUserPasswordMapper;
import com.nodecollege.cloud.service.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * userService
 *
 * @author LC
 * @date 2019/6/13 15:49
 */
@Service
public class UserServiceImpl implements UserService {

    private static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Value("${fdfsGroup:/ncimg/}")
    private String fdfsGroup;

    @Autowired
    private UpmsUserMapper upmsUserMapper;

    @Autowired
    private UpmsUserPasswordMapper upmsUserPasswordMapper;

    @Autowired
    private PasswordPolicyService passwordPolicyService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private UpmsTenantMapper upmsTenantMapper;

    @Autowired
    private UserInvitationService userInvitationService;

    @Autowired
    private FileService fileService;

    @Autowired
    private UpmsMemberMapper upmsMemberMapper;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 查询所有用户信息
     */
    @Override
    public NCResult<UpmsUser> list(QueryVO<UpmsUser> query) {
        List<UpmsUser> list = new ArrayList<>();
        Long total = 0L;
        if (NCConstants.INT_NEGATIVE_1.equals(query.getPageSize())) {
            list = upmsUserMapper.selectUserListByMap(query.toMap());
            total = NCUtils.isNullOrEmpty(list) ? 0 : Long.parseLong(list.size() + "");
        } else {
            Page page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
            if (query.isSort()) {
                page.setOrderBy(query.getSortKey() + " " + query.getSortDirection());
            }
            list = upmsUserMapper.selectUserListByMap(query.toMap());
            total = page.getTotal();
        }
        return NCResult.ok(list, total);
    }

    /**
     * 根据用户账号获取用户信息
     *
     * @param account
     */
    @Override
    public UpmsUser getUserByAccount(String account) {
        UpmsUser user = new UpmsUser();
        user.setAccount(account);
        List<UpmsUser> result = upmsUserMapper.selectUserListByMap(new QueryVO<>(user).toMap());
        NCUtils.nullOrEmptyThrow(result, new UpmsException("-1", "根据账号未获取到用户信息"));
        return result.get(0);
    }

    /**
     * 用户注册
     *
     * @param loginVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(LoginVO loginVO) {
        NCUtils.nullOrEmptyThrow(loginVO.getPassword(), new UpmsException("-1", "用户密码不能为空"));
        NCUtils.nullOrEmptyThrow(loginVO.getTelephone(), new UpmsException("-1", "用户电话不能为空"));
        if (!RegularExpUtils.checkTelephone(loginVO.getTelephone())) {
            throw new UpmsException("-1", "电话格式不正确！");
        }
        // 1 校验账号是否已经注册
        UpmsUser query = new UpmsUser();
        query.setTelephone(loginVO.getTelephone());
        List<UpmsUser> result = upmsUserMapper.selectUserListByMap(new QueryVO<>(query).toMap());
        NCUtils.notNullOrNotEmptyThrow(result, new UpmsException("-1", "此电话已注册"));

        // 校验密码规则
        passwordPolicyService.checkRegisterPolicy(loginVO.getPassword(), loginVO.getTelephone());

        // 2 保存用户信息
        UpmsUser addUser = new UpmsUser();
        addUser.setAccount(loginVO.getTelephone());
        addUser.setTelephone(loginVO.getTelephone());
        addUser.setCreateTime(new Date());
        addUser.setState(NCConstants.INT_1);
        addUser.setSalt(PasswordUtil.getRandomSalt());
        addUser.setPassword(PasswordUtil.md5(loginVO.getPassword(), addUser.getSalt()));
        addUser.setFirstLogin(NCConstants.INT_1);
        upmsUserMapper.insertSelective(addUser);
        userInvitationService.checkInviteAndAddMember(addUser);
    }

    /**
     * 更新用户信息
     *
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UpmsUser user, ApiDataPower apiDataPower) {
        NCUtils.nullOrEmptyThrow(user.getUserId(), new UpmsException("-1", "更新用户信息失败，用户主键不能为空！"));
        NCUtils.nullOrEmptyThrow(user.getAccount(), new UpmsException("-1", "更新用户信息失败，用户账号不能为空！"));
        NCUtils.nullOrEmptyThrow(user.getNickname(), new UpmsException("-1", "更新用户信息失败，用户名称不能为空！"));
        NCUtils.nullOrEmptyThrow(user.getTelephone(), new UpmsException("-1", "更新用户信息失败，用户电话不能为空！"));
        UpmsUser oldUser = getUserByUserId(user.getUserId());
        NCUtils.nullOrEmptyThrow(oldUser, new UpmsException("", "该用户不存在！"));

        if (!RegularExpUtils.checkTelephone(user.getTelephone())) {
            throw new UpmsException("-1", "电话格式不正确！");
        }

        UpmsUser queryUser = new UpmsUser();
        queryUser.setAccount(user.getAccount());
        List<UpmsUser> exList = upmsUserMapper.selectUserListByMap(new QueryVO<>(queryUser).toMap());
        if (exList.size() == 1 && !exList.get(0).getUserId().equals(user.getUserId())) {
            throw new UpmsException("-1", "该账号已存在！");
        }

        queryUser = new UpmsUser();
        queryUser.setTelephone(user.getTelephone());
        exList = upmsUserMapper.selectUserListByMap(new QueryVO<>(queryUser).toMap());
        if (exList.size() == 1 && !exList.get(0).getUserId().equals(user.getUserId())) {
            throw new UpmsException("-1", "该手机号已存在！");
        }

        UpmsUser updateUser = new UpmsUser();
        updateUser.setUserId(user.getUserId());
        updateUser.setNickname(user.getNickname());
        updateUser.setAccount(user.getAccount());
        updateUser.setTelephone(user.getTelephone());
        updateUser.setEmail(user.getEmail());
        updateUser.setSex(user.getSex());
        updateUser.setBirthday(user.getBirthday());
        upmsUserMapper.updateByPrimaryKeySelective(updateUser);
        if (!StringUtils.isEmpty(user.getAccount())) {
            LoginUser loginUser = ThreadUserUtils.getLoginUser();
            loginUser.setAccount(user.getAccount());
            loginUser.setInfoRandom(NCUtils.getUUID());
            redisUtils.set(UpmsConstants.USER_LOGIN_INFO + loginUser.getAccessToken(), loginUser, loginUser.getExpire());
        }
        clearUserCache(user.getUserId());
    }

    /**
     * 删除用户信息
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delUser(Long id, ApiDataPower apiDataPower) {
        UpmsUser user = getUserByUserId(id);
        NCUtils.nullOrEmptyThrow(user, new UpmsException("-1", "用户删除失败，根据id未查询到用户信息！"));

        UpmsMember queryMember = new UpmsMember();
        queryMember.setUserId(id);
        List<UpmsMember> exMember = upmsMemberMapper.selectListByMap(new QueryVO<>(queryMember).toMap());
        NCUtils.notNullOrNotEmptyThrow(exMember, new UpmsException("", "该用户存在绑定的成员信息，不能删除！"));

        user.setState(NCConstants.INT_NEGATIVE_1);
        upmsUserMapper.updateByPrimaryKeySelective(user);
        clearUserCache(id);
    }

    /**
     * 重置密码, 运维人员使用
     *
     * @param upmsUser
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPwd(UpmsUser upmsUser) {
        NCUtils.nullOrEmptyThrow(upmsUser.getUserId(), new UpmsException("", "用户id不能为空！"));
        // 1 根据用户id获取用户信息
        UpmsUser user = getUserByUserId(upmsUser.getUserId());
        NCUtils.nullOrEmptyThrow(user, new UpmsException("-1", "重置密码失败，根据id获取用户信息失败！"));
        // 2 获取默认密码配置数据
//        List<Config> config = configDao.getConfigsByCodeAndTenantId(ConfigConstants.DEFAULT_PASSWORD, query.getTenantId());
//        if (config.isEmpty()) {
//            throw new UpmsException("-1", "重置密码失败，获取默认密码失败，请联系管理员处理！");
//        }
        // 3 旧密码存入密码表中
        UpmsUserPassword userPassword = new UpmsUserPassword();
        userPassword.setUserId(upmsUser.getUserId());
        userPassword.setSalt(user.getSalt());
        userPassword.setPassword(user.getPassword());
        userPassword.setCreateTime(new Date());
        upmsUserPasswordMapper.insertSelective(userPassword);

        // 4 将新密码进行保存更新
        user.setSalt(PasswordUtil.getRandomSalt());
        user.setPassword(PasswordUtil.md5("123456", user.getSalt()));
        user.setFirstLogin(0);
        upmsUserMapper.updateByPrimaryKeySelective(user);
        clearUserCache(upmsUser.getUserId());
    }

    /**
     * 修改密码
     *
     * @param userId
     * @param oldPassword
     * @param newPassword
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePwd(Long userId, String oldPassword, String newPassword, ApiDataPower apiDataPower) {
        UpmsUser user = getUserByUserId(userId);
        NCUtils.nullOrEmptyThrow(user, new UpmsException("-1", "修改密码失败，根据用户id未获取到用户信息！"));
        oldPassword = PasswordUtil.md5(oldPassword, user.getSalt());
        if (!oldPassword.equals(user.getPassword())) {
            throw new UpmsException("-1", "修改密码失败，旧密码输入错误！");
        }

        // 校验新密码是否满足规则
        passwordPolicyService.checkRegisterPolicy(newPassword, user.getAccount());

        // 登陆成功后校验密码是否和历史密码一致
        passwordPolicyService.checkUserLoginSuccessPolicy(userId, 1);

        // 将旧密码存于密码表中
        UpmsUserPassword userPassword = new UpmsUserPassword();
        userPassword.setSalt(user.getSalt());
        userPassword.setPassword(user.getPassword());
        userPassword.setCreateTime(new Date());
        upmsUserPasswordMapper.insertSelective(userPassword);

        // 更新新密码
        user.setSalt(PasswordUtil.getRandomSalt());
        user.setPassword(PasswordUtil.md5(newPassword, user.getSalt()));
        user.setFirstLogin(1);
        upmsUserMapper.updateByPrimaryKeySelective(user);

        // 清除登陆失败次数
        passwordPolicyService.deleteUserLoginFileNum(user.getAccount());
        clearUserCache(userId);
    }

    /**
     * 切换默认租户
     *
     * @param loginUser
     */
    @Override
    public void changeDefaultTenant(LoginUser loginUser) {
        NCUtils.nullOrEmptyThrow(loginUser.getTenantId(), new UpmsException("", "租户id不能为空！"));

        UpmsTenant exTenant = upmsTenantMapper.selectByPrimaryKey(loginUser.getTenantId());
        NCUtils.nullOrEmptyThrow(exTenant, new UpmsException("", "该租户不存在！"));

        UpmsUser user = getUserByUserId(loginUser.getUserId());
        NCUtils.nullOrEmptyThrow(user, new UpmsException("", "该用户不存在！"));

        QueryVO<UpmsMember> queryMember = new QueryVO<>(new UpmsMember());
        queryMember.getData().setTenantId(loginUser.getTenantId());
        queryMember.getData().setUserId(loginUser.getUserId());
        List<UpmsMember> exMember = upmsMemberMapper.selectListByMap(queryMember.toMap());
        NCUtils.nullOrEmptyThrow(exMember, new UpmsException("", "不是该企业成员！"));

        UpmsUser updateUser = new UpmsUser();
        updateUser.setUserId(user.getUserId());
        updateUser.setTenantId(loginUser.getTenantId());
        upmsUserMapper.updateByPrimaryKeySelective(updateUser);

        loginUser.setAccount(user.getAccount());
        memberService.initMemberDataPower(loginUser);
        loginUser.setInfoRandom(NCUtils.getUUID());
        redisUtils.set(UpmsConstants.USER_LOGIN_INFO + loginUser.getAccessToken(), loginUser, loginUser.getExpire());
        clearUserCache(loginUser.getTenantId());
    }

    /**
     * 根据昵称查询用户信息
     *
     * @param queryVO
     * @return
     */
    @Override
    public NCResult<UpmsUser> getUserListByNickname(QueryVO<UpmsUser> queryVO) {
        NCUtils.nullOrEmptyThrow(queryVO.getData().getNickname(), new UpmsException("", "请输入昵称"));
        Page page = PageHelper.startPage(queryVO.getPageNum(), queryVO.getPageSize());
        List<UpmsUser> list = upmsUserMapper.getUserListByNickname(queryVO.toMap());
        Long total = page.getTotal();
        return NCResult.ok(list, total);
    }

    /**
     * 根据用户id查询用户信息
     *
     * @param queryVO
     * @return
     */
    @Override
    public List<UpmsUser> getUserListByQuery(QueryVO queryVO) {
        NCUtils.nullOrEmptyThrow(queryVO.getLongList(), new UpmsException("", "主键列表不能为空！"));
        List<UpmsUser> list = new ArrayList<>(queryVO.getLongList().size());
        for (int i = 0; i < queryVO.getLongList().size(); i++){
            UpmsUser user = getUserByUserId(queryVO.getLongList().get(i));
            if (user != null){
                list.add(user);
            }
        }
        return list;
    }

    /**
     * 根据用户id获取用户信息
     *
     * @param userId
     * @return
     */
    @Override
    public UpmsUser getUserByUserId(Long userId) {
        String userKey = UpmsConstants.REDIS_USER_INFO + userId;
        UpmsUser user = redisUtils.get(userKey, UpmsUser.class);
        if (user == null) {
            user = upmsUserMapper.selectByPrimaryKey(userId);
            if (user != null && StringUtils.isNotBlank(user.getAvatar())){
                user.setAvatar(fdfsGroup + user.getAvatar());
                int temp = user.getAvatar().indexOf(".");
                user.setAvatarThumb(user.getAvatar().substring(0, temp) + "_80x80" + user.getAvatar().substring(temp));
            }
            int exp = new Random().nextInt(60 * 10);
            redisUtils.set(userKey, user, 60 * 60 * 2 + exp);
        }
        return user;
    }

    /**
     * 清除用户缓存
     */
    @Override
    public void clearUserCache(Long userId) {
        redisUtils.delete(UpmsConstants.REDIS_USER_INFO + userId);
    }

    /**
     * 上传头像
     *
     * @param avatarFile
     * @param userId
     * @return
     */
    @Override
    public UpmsUser uploadAvatar(MultipartFile avatarFile, Long userId) {
        NCUtils.nullOrEmptyThrow(avatarFile, new UpmsException("", "头像文件不能为空！"));
        NCUtils.nullOrEmptyThrow(userId, new UpmsException("", "用户id不能为空！"));
        UpmsUser user = getUserByUserId(userId);
        NCUtils.nullOrEmptyThrow(user, new UpmsException("-1", "该用户不存在！"));

        UpmsFile upmsFile = new UpmsFile();
        upmsFile.setUserId(userId);
        upmsFile.setFileType(NCConstants.INT_1);
        upmsFile.setFilePurpose(NCConstants.INT_0);
        upmsFile = fileService.uploadFileThumb(avatarFile, upmsFile);

        UpmsUser update = new UpmsUser();
        update.setUserId(userId);
        update.setAvatar(upmsFile.getFilePath());
        upmsUserMapper.updateByPrimaryKeySelective(update);
        user.setAvatar(upmsFile.getFilePath());
        clearUserCache(userId);
        return user;
    }
}
